
#include <strings.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <aio.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>

#include "LocalFile.h"

namespace lzpLib{

LocalFile::LocalFile(const std::string &url):url_(url), fd_(-1), length_(-1){
}

int LocalFile::open(){
    assert(url_.find("file://") == 0);
    int fd = ::open(url_.c_str()+7, O_RDONLY);
    printf("local file open %s fd %d\n", url_.c_str()+7, fd);
    if(fd <= 0) {
//		postOpen(false);
        return -1;
    }
    struct stat s;
    int ret = ::fstat(fd, &s);
    if(ret == 0 && S_ISREG(s.st_mode)) {
        fd_ = fd;
        length_ = s.st_size;
		m_bOpenSucc = true;
//		postOpen(true);
        return 0;
    }
    ::close(fd);
//	postOpen(false);
    return -1;
}

int LocalFile::close(){
//    postOpen(false);
	if(fd_ != -1) {
        ::close(fd_);
    }
    return 0;
}

int LocalFile::read(char* buffer, unsigned int *length){
    assert(fd_ != -1);
    //printf("local file read length %d fd %d\n", *length, fd_);
    int ret = ::read(fd_, buffer, *length);
    *length = ret >=0 ? ret : 0;
    ret = ret >=0 ? 0 : -1;
    return -1;
}

//static void aio_complete_cb(sigval_t sigval){
//    struct aiocb* cb = (struct aiocb*)sigval.sival_ptr;
//    DtaFile::AsyncCallback* callback = *(DtaFile::AsyncCallback**)(cb+1);
//    int ret = aio_error(cb);
//    if (ret == 0) {
//        /* Request completed successfully, get the return status */
//        int len = aio_return(cb);
//        lseek(cb->aio_fildes, len, SEEK_CUR);
//        if(len < (int)cb->aio_nbytes) {
//            callback->complete(BesTV_EOF, len);
//        }else{
//            callback->complete(BesTV_OK, len);
//        }
//    } else if(ret == ECANCELED){
//        callback->complete(BesTV_Abort, 0);
//    } else {
//        printf("aio_complete_cb fail %d\n", ret);
//        callback->complete(BesTV_Fail, 0);
//    }
//    free(cb);
//}

//void* LocalFile::readAsync(char* buffer, unsigned int length, AsyncCallback &callback){
//    assert(fd_ != -1);
//    struct aiocb* cb = (struct aiocb*)malloc(sizeof(struct aiocb)+sizeof(AsyncCallback*));
//    bzero(cb, sizeof(struct aiocb)+sizeof(AsyncCallback*));
//
//    cb->aio_fildes = fd_;
//    cb->aio_buf = buffer;
//    cb->aio_nbytes = length;
//    cb->aio_offset = tell();
//    printf("local file readAsync length %d off %d fd %d %p\n", length, (int)cb->aio_offset, fd_, cb);
//    //thread callback
//    cb->aio_sigevent.sigev_notify = SIGEV_THREAD;
//    cb->aio_sigevent.sigev_notify_function = aio_complete_cb;
//    cb->aio_sigevent.sigev_notify_attributes = NULL;
//    cb->aio_sigevent.sigev_value.sival_ptr = cb;
//    AsyncCallback** ppa = (AsyncCallback**)(cb+1);
//    *ppa = &callback;
//    int ret = aio_read(cb);
//    if(ret != 0) {
//        printf("free aio %p", cb);
//        free(cb);
//        return NULL;
//    }
//    return cb;
//}

int LocalFile::cancel(void* asyncReq){
    assert(asyncReq != NULL);
    if(asyncReq == NULL) {
        return -1;
    }
    printf("local file cancel fd %d\n", fd_);
    int ret = aio_cancel(fd_, (struct aiocb*)asyncReq);
    if(ret == AIO_CANCELED) {
        return 0;
    } else {
        return -1;
    }
}

long long LocalFile::seek(long long offset, int whence){
    assert(fd_ != -1);
    printf("local file seek whence %d off %lld fd %d\n", whence, offset, fd_);
    return ::lseek(fd_, offset, whence);
}

long long LocalFile::tell(){
    assert(fd_ != -1);
    printf("local file tell fd %d\n", fd_);
    return ::lseek(fd_, 0, SEEK_CUR);
}

long long LocalFile::length(){
    printf("local file length fd %d len %lld\n", fd_, length_);
    assert(fd_ != -1);
    return length_;
}

long long LocalFile::available(){
    printf("local file available fd %d\n", fd_);
    assert(fd_ != -1);
    long long len = length();
    long long pos = tell();
    if(pos == -1) {
        printf("local file available fail\n");
        return -1;
    }
    printf("local file available %lld\n", len - pos);
    return len - pos;
}

LocalFile::~LocalFile(){
    if(fd_ != -1) {
        ::close(fd_);
    }
}

}

